package com.nulldev.util.os;

import java.awt.AWTException;

import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.TrayIcon.MessageType;
import java.util.Locale;

import com.nulldev.util.image.ImageUtil;
import com.nulldev.util.io.FileUtil;
import com.nulldev.util.java.JVMUtil;
import com.nulldev.util.java.ProcessUtil;
import com.nulldev.util.java.ProcessUtil.ProcessUtilRead;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;
import com.nulldev.util.math.MathUtil;
import com.nulldev.util.os.linux.Distro;
import com.nulldev.util.os.linux.DistroDetector;
import com.nulldev.util.os.linux.de.DEDetector;
import com.nulldev.util.os.linux.de.DesktopEnvironment;
import com.nulldev.util.os.notifications.mExecutor.MessagePriority;

public final class OSUtil {
	private static final Logger log = LoggerFactory.getLogger(true, true);
	
  /**
   * types of Operating Systems
   */
  public enum OSType {
    Windows("Windows"),
    MacOS("Mac OS"),
    Linux("GNU/Linux"),
    Solaris("Solaris"),
    BSD("BSD"),
    Other("N/A");
	  
	private final String displayOS;
	private OSType(final String displayOS) {
		this.displayOS = displayOS;
	}
	
	@Override
	public String toString() {
		return this.displayOS;
	}
  };
  
  public static enum Windows_Type {
	  WINDOWS_10(10.0, "Windows 10"),
	  WINDOWS_8_1(6.3, "Windows 8.1"),
	  WINDOWS_8(6.2, "Windows 8"),
	  WINDOWS_7(6.1, "Windows 7"),
	  WINDOWS_VISTA(6, "Windows Vista"),
	  WINDOWS_XP_P64(5.2, "Windows XP [Professional x64]"),
	  WINDOWS_XP(5.1, "Windows XP"),
	  WINDOWS_2000(5.0, "Windows 2000"),
	  WINDOWS_ME(4.9, "Windows ME"),
	  WINDOWS_98(4.10, "Windows 98"),
	  WINDOWS_95(4, "Windows 95"),
	  WINDOWS_NT_3_51(3.51, "Windows NT 3.51"),
	  WINDOWS_NT_3_5(3.5, "Windows NT 3.5"),
	  WINDOWS_3_2(3.2, "Windows 3.2"),
	  
	  N_A(-1, "N/A")
	  ;
	  
	  private final double ntVer;
	  private final String ntString;
	  private Windows_Type(final double ntVer, final String ntString) {
		  this.ntVer = ntVer;
		  this.ntString = ntString;
	  }
	  
	  @Override
	  public String toString() {
		  return this.ntString;
	  }
	  
	  public String getNTString() {
		  return this.ntString;
	  }
	  
	  public double getNT() {
		  return this.ntVer;
	  }
	  
	  public static Windows_Type getType() {
		  if (!OSUtil.isWindows()) {
			  return N_A;
		  }
		  final double ntVerI = MathUtil.safeParseD(System.getProperty("os.version", "generic"), -1);
		  for (final Windows_Type type : values()) {
			  if (type.getNT() == ntVerI) {
				  return type;
			  }
		  }
		  return N_A;
	  }
  }

  // cached result of OS detection
  protected static OSType detectedOS;

  /**
   * detect the operating system from the os.name System property and cache
   * the result
   *
   * @returns - the operating system detected
   */
  public static OSType getOperatingSystemType() {
    if (detectedOS == null) {
      String OS = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH);
      if ((OS.indexOf("mac") >= 0) || (OS.indexOf("darwin") >= 0)) {
        detectedOS = OSType.MacOS;
      } else if (OS.indexOf("win") >= 0) {
        detectedOS = OSType.Windows;
      } else if (OS.indexOf("nux") >= 0) {
        detectedOS = OSType.Linux;
      } else if (OS.indexOf("solaris") >= 0 || OS.indexOf("sunos") >= 0) {
    	detectedOS = OSType.Solaris;
      } else if (OS.indexOf("BSD") >= 0) {
    	detectedOS = OSType.BSD;
      } else {
        detectedOS = OSType.Other;
      }
    }
    return detectedOS;
  }
  
  public static Distro getLinuxDistro() {
	  if (!OSUtil.isLinux()) {
		  return Distro.UNKNOWN;
	  }
	  return DistroDetector.detect().getDistro();
  }
  
  public static DesktopEnvironment getDE() {
	  return DEDetector.detect();
  }

  public static void reset() {
	  detectedOS = null;
	  getOperatingSystemType();
  }

  public static boolean isWindows() {
	  return getOperatingSystemType() == OSType.Windows;
  }
  
  public static boolean isLinux() {
	  return getOperatingSystemType() == OSType.Linux;
  }
  
  //private static final SystemTray tray = SystemTray.getSystemTray();
  private static boolean initd;
  //private static final TrayIcon ic = new TrayIcon(ImageUtil.getLogo24(), "nullUtil Notificator");
  
  /**
   * Make sure to use mExecutor first.
   * @param title
   * @param message
   * @param type
   */
  public static void displayNotification(final String title, final String message, final MessageType type) {
	  if (!initd) {
		//  try {
			//tray.add(ic);
			//initd = true;
		//} catch (AWTException e) {
		//}
	  }
	  try {
		 // ic.displayMessage(title, message, type);
	  }catch (Exception e) {}
  }
  
  public static void displayNotification(final String title, final String message, final MessagePriority type) {
	  if (true) {
		  return;
	  }
	  if (!initd) {
		  try {
			//tray.add(ic);
			initd = true;
		} catch (Exception e) {
		}
	  }
	  if (type == MessagePriority.CRITICAL) {
		  try {
			  //ic.displayMessage(title, message, MessageType.ERROR);
		  }catch (Exception e) {}
	  }else if (type == MessagePriority.WARNING) {
		  try {
			  //ic.displayMessage(title, message, MessageType.WARNING);
		  }catch (Exception e) {}
	  }else if (type == MessagePriority.NORMAL) {
		  try {
			  //ic.displayMessage(title, message, MessageType.INFO);
		  }catch (Exception e) {}
	  }else if (type == MessagePriority.LOW) {
		  try {
			  //ic.displayMessage(title, message, MessageType.NONE);
		  }catch (Exception e) {}
	  }
  }
  
  public static class PackageUtil {
	  
	  public static boolean isPackage(final String package_name) {
		  try {
			  if (OSUtil.getOperatingSystemType() == OSType.Linux) {
				  return FileUtil.safeCreate("/bin/" + package_name).exists() || FileUtil.safeCreate("/usr/bin/" + package_name).exists();
			  }
			  return false;
		  }catch (Exception e) {
			  return false;
		  }
	  }
	  
	  public static String getPackageManager() {
		  if (OSUtil.getOperatingSystemType() == OSType.Linux) {
			  if (isPackage("emerge")) {
				  return "emerge";
			  }else if (isPackage("apt-get")) {
				  return "apt-get";
			  }else if (isPackage("apt")) {
				  return "apt";
			  }else if (isPackage("pacman")) {
				  return "pacman";
			  }else if (isPackage("pacaur")) {
				  return "pacaur";
			  }else if (isPackage("yaourt")) {
				  return "yaourt";
			  }
		  }
		  return "N/A";
	  }
	  
	  public static void elevateActive(final String command, final ProcessUtilRead event) {
		  if (OSUtil.getOperatingSystemType() == OSType.Linux) {
			  if (isPackage("gksudo")) {
				  try {
					  ProcessUtil.ProcessUtilActive.execCmd("gksudo -P -m \"nullUtil2.elevator\" | " + command, event);
				  }catch (Exception e) {
					  e.printStackTrace();
				  }
			  }	else if (isPackage("gksu")) {
				  try {
					  ProcessUtil.ProcessUtilActive.execCmd("gksu -P -m \"nullUtil2.elevator\" | " + command, event);
				  }catch (Exception e) {
					  e.printStackTrace();
				  }
			  } else if (isPackage("pkexec")) {
				  try {
					  ProcessUtil.ProcessUtilActive.execCmd("pkexec " + command, event);
				  }catch (Exception e) {
					  e.printStackTrace();
				  }
			  }
		  }
	  }
	  
	  public static void elevateActive_Desc(final String command, final ProcessUtilRead event, final String desc) {
		  if (OSUtil.getOperatingSystemType() == OSType.Linux) {
			  if (isPackage("gksudo")) {
				  try {
					  ProcessUtil.ProcessUtilActive.execCmd("gksudo -P -m \"" + desc + "\" | " + command, event);
				  }catch (Exception e) {
					  e.printStackTrace();
				  }
			  }	else if (isPackage("gksu")) {
				  try {
					  ProcessUtil.ProcessUtilActive.execCmd("gksu -P -m \"" + desc + "\" | " + command, event);
				  }catch (Exception e) {
					  e.printStackTrace();
				  }
			  } else if (isPackage("pkexec")) {
				  try {
					  ProcessUtil.ProcessUtilActive.execCmd("pkexec " + command, event);
				  }catch (Exception e) {
					  e.printStackTrace();
				  }
			  }
		  }
	  }
	  
	  public static String elevate(final String command) {
		  if (OSUtil.getOperatingSystemType() == OSType.Linux) {
			  if (isPackage("gksudo")) {
				  try {
					  return ProcessUtil.execCmd("gksudo -P -m \"nullUtil2.elevator\" | " + command);
				  }catch (Exception e) {
					  e.printStackTrace();
				  }
			  }	else if (isPackage("gksu")) {
				  try {
					  return ProcessUtil.execCmd("gksu " + command);
				  }catch (Exception e) {
					  e.printStackTrace();
				  }
			  } else if (isPackage("pkexec")) {
				  try {
					  return ProcessUtil.execCmd("pkexec " + command);
				  }catch (Exception e) {
					  e.printStackTrace();
				  }
			  }
		  }
		  return "N/A";
	  }

	  public static String installModule(final String pkg_toInstall) {
		final String pkg = getPackageManager();
		if (!pkg.equals("N/A")) {
			if (pkg.equals("apt-get")) {
				return elevate("apt-get install -y " + pkg_toInstall);
			}else if (pkg.equals("apt")) {
				return elevate("apt install -y " + pkg_toInstall);
			}else if (pkg.equals("pacman")) {
				return elevate("pacman --noconfirm -S " + pkg_toInstall);
			}else if (pkg.equals("pacaur")) {
				log.error("Unsupported package manager 'pacaur'.");
			}else if (pkg.equals("yaourt")) {
				log.error("Unsupported package manager 'yaourt'.");
			}else if (pkg.equals("emerge")) {
				return elevate("emerge -a " + pkg_toInstall);
			}
		}
		return "N/A";
	  }
	  
	  public static void installModuleActive(final String pkg_toInstall, final ProcessUtilRead event) {
		final String pkg = getPackageManager();
		if (!pkg.equals("N/A")) {
			if (pkg.equals("apt-get")) {
				elevateActive("apt-get install -y " + pkg_toInstall, event);
			}else if (pkg.equals("apt")) {
				elevateActive("apt install -y " + pkg_toInstall, event);
			}else if (pkg.equals("pacman")) {
				elevateActive("pacman --noconfirm -S " + pkg_toInstall, event);
			}else if (pkg.equals("pacaur")) {
				log.error("Unsupported package manager 'pacaur'.");
			}else if (pkg.equals("yaourt")) {
				log.error("Unsupported package manager 'yaourt'.");
			}else if (pkg.equals("emerge")) {
				elevateActive("emerge -a " + pkg_toInstall, event);
			}
		}
	  }

	public static boolean isLib(final String libName) {
		if (!isLinux()) {
			return false;
		}
		return FileUtil.safeCreate("/lib/" + libName).exists() || FileUtil.safeCreate("/usr/lib/" + libName).exists();
	}
	
	public static boolean isLibJ(final String libName) {
		if (OSUtil.isLinux()) {
			if (JVMUtil.is64()) {
				return FileUtil.safeCreate("/usr/java/packages/lib/amd64/" + libName).exists();
			}else {
				return FileUtil.safeCreate("/usr/java/packages/lib/i386/" + libName).exists();
			}
		}
		return false;
	}
  }

  public static String getOperatingSystemString() {
	  return System.getProperty("os.name", "generic") + ", " + System.getProperty("os.version", "generic");
  }

  public static boolean isMac() {
	  return getOperatingSystemType() == OSType.MacOS;
  }
  
  public static void main(final String[] args) {
	  log.info("Loading OS demo...");
	  log.info("OS.Type = " + getOperatingSystemType());
	  log.info("OS.getWindowsBuild(OS) = " + Windows_Type.getType());
	  log.info("OS.Linux.Distro = " + getLinuxDistro());
	  log.info("OS.DE = " + getDE());
  }
}